from pydantic import BaseModel, Field
from typing import Optional, Any, Callable, Dict
from fastapi.responses import JSONResponse
from datetime import datetime
from fastapi import status
from functools import wraps
from app.core.exceptions import RobotException, ErrorCode, MockDataErrorException
from fastapi import HTTPException
from app.core import setting


class StandardResponse(BaseModel):
    code: int = Field(..., description="Status code")
    created: str = Field(..., description="The date when return response")
    data: Optional[Any] = Field(default={}, description="response data")


class CommonFailData(BaseModel):
    error_code: int
    error: str
    detail: str


class CommonFailResponse(StandardResponse):
    data: CommonFailData = Field(..., description="Error description")

class EmptyResponse(StandardResponse):
    data: Dict[Any, Any] = Field(default={})


def success_response(code: status, data: Optional[Dict[Any, Any]] = None) -> JSONResponse:
    now = datetime.now()
    response_data = {
        "code": code,
        "created": now.strftime('%Y-%m-%d %H:%M:%S'),
        "data": data
    }
    return JSONResponse(status_code=code, content=response_data)


def error_response(code: status, data: Optional[Dict[Any, Any]]) -> JSONResponse:
    now = datetime.now()
    response_data = {
        "code": code,
        "created": now.strftime('%Y-%m-%d %H:%M:%S'),
        "data": data
    }
    return JSONResponse(status_code=code, content=response_data)

def standardize_response(statu_code: status):
    def standardize_response_func(func: Callable) -> Callable:
        @wraps(func)
        async def wrapper(*args, **kwargs):
            try:
                result = await func(*args, **kwargs)
                if not isinstance(result, dict):
                    return result
                else:
                    # 否则包装成成功响应
                    return success_response(data=result, code=statu_code)
            except HTTPException as e:
                return error_response(code=e.status_code,
                                      data={
                                          "error_code": e.status_code,
                                          "error": e.detail,
                                          "detail": f"HTTPException: {e.detail}"
                                      })
            except RobotException as e:
                return error_response(code=status.HTTP_406_NOT_ACCEPTABLE,
                                      data={
                                          "error_code": e.code,
                                          "error": e.error,
                                          "detail": e.detail
                                      })
            except ValueError as e:
                return error_response(code=status.HTTP_406_NOT_ACCEPTABLE,
                                      data={
                                          "error_code": ErrorCode.VALIDATION_ERROR.code,
                                          "error": ErrorCode.VALIDATION_ERROR.message,
                                          "detail": f"Value Validation Error: {e}"
                                      }

                )
            except MockDataErrorException as e:
                return error_response(code=setting.mock_type.value,
                                      data={
                                          "error_code": e.code,
                                          "error": e.error,
                                          "detail": e.detail
                                      })
            except Exception as e:
                return error_response(code=status.HTTP_400_BAD_REQUEST,
                                      data={
                                          "error_code": ErrorCode.UNKNOWN_ERROR.code,
                                          "error": ErrorCode.UNKNOWN_ERROR.message,
                                          "detail": str(e)
                                      })
            finally:
                pass

        return wrapper
    return standardize_response_func
